/*
MujMail - Simple mail client for J2ME
Copyright (C) 2006 Nguyen Son Tung <n.sontung@gmail.com>
Copyright (C) 2006 Martin Stefan <martin.stefan@centrum.cz>
Copyright (C) 2008 David Hauzar <david.hauzar.mujmail@gmail.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package mujmail;

import java.util.Vector;
import javax.microedition.lcdui.AlertType;
import lcduilwuit.Form;
import lcduilwuit.Command;
import lcduilwuit.List;
import lcduilwuit.Displayable;
import lcduilwuit.StringItem;
import lcduilwuit.Choice;
import com.sun.lwuit.Label;
import com.sun.lwuit.Image;
import com.sun.lwuit.TextArea;
import com.sun.lwuit.Dialog;
import mujmail.util.Functions;
import com.sun.lwuit.Component;
import com.sun.lwuit.events.ActionListener;
import com.sun.lwuit.events.ActionEvent;
//#ifdef MUJMAIL_HTML
import mujmail.html.Browser;
import mujmail.html.Parser;
//#endif
/**
 * Displays the mail header as well as whole mail
 * .
 */

public class MailForm extends Form implements Runnable, ActionListener {
    public static final int BP_VIEWING_MODE_AS_NOT_SPECIFIED=0;
    public static final int BP_VIEWING_MODE_AS_TEXT=1;
    public static final int BP_VIEWING_MODE_AS_HTML=2;
    public static final int BP_VIEWING_MODE_AS_IMAGE=3;
    public static final int BP_VIEWING_MODE_AS_SOUND=4;
    public static final int BP_VIEWING_MODE_AS_NO_VIEW=5;
    private int bpViewingMode;
    Component bodyPart;
    static final int MAX_SIZE_TEXT=5000;
    private static final boolean DEBUG = false;
    private Displayable prevScreen = this;
    // graphical modes
    public static final byte MODE_LIST = 0; //when we only list the bodyparts of the mail
    public static final byte MODE_BASIC = 1; //when we display the first viewable bodypart
    public static final byte MODE_BROWSE = 2; //when we display other bodyparts than the first viewable
    static final byte LOAD_BODY = 0;
    static final byte REDOWNLOAD_BODY = 1;
    byte runMode = LOAD_BODY;
    MujMail mujMail; // TODO (Betlista): this doesn't need to here while Mujmail have public static field mujmail
    TheBox callBox; //the box that called this MailForm
    Command back, listAttachments, showAttachment, deleteAttachment, showAddresses,  addMailToBook;
    //#ifdef MUJMAIL_FS
    Command exportToFS;
    //#endif
     // exports bodypart to filesystem
    Command exportBPToFS;
    Command forward, reply, replyAll, quotedReply, /*delete,*/ edit;
    //ParentCommand reply;
    List attchList, mailAdrList;
    Form headerForm;
    MessageHeader msgHeader; //header of the message that is being displayed
    byte bodyPartToRedown; //the particular bodypart that should be redownloaded
    //stuffs for displaying a text bodypart
    int currDisplay = 0; //current text page
    byte contextID = MODE_BASIC;
    byte currAttachmentID = 0;
    byte firstViewable = -1;
    /** defines if the bodypart have to be downloaded before reading */
    boolean newTextSelected = false;
    boolean newConvertedTextSelected = false;
    // a Vector of displays that stores the text bodyparts
    Vector textBodyDisplays;
    // contains a text of a text bodypart,
    String textBodyString;
    /** The viewing mode of the body part */

    /**
     * Shows previous screen, which reference is stored in {@link #prevScreen}
     * variable. Important thing is to set the {@link #contextID} variable, see
     * the comment in {@link #setContext(byte)} method.
     *
     * @see #prevScreen
     * @see #contextID
     * @see #setContext(byte)
     */
    public void showPreviousScreen() {
        MujMail.mujmail.getDisplay().setCurrent(prevScreen);
    }

    private void updateEditButton() {
       /* removeCommand(edit);
        if (callBox instanceof InBox) {
            edit = new Command(Lang.get(Lang.EXTRA_BOUNCE), Command.ITEM, 10);
        } else {
            edit = new Command(Lang.get(Lang.BTN_EDIT), Command.ITEM, 10);
        }
        addCommand(edit);*/
        removeCommand(edit);
         if ((callBox instanceof OutBox)) {
             addCommand(edit);
         }
    }

    //#ifdef MUJMAIL_HTML
    /*private void displayHTMLBodyPart( final Graphics g ) {
          if (DEBUG) System.out.println("DEBUG MailForm.displayHTMLBodyPart(Graphics)");
        BPViewingModes.ViewingModesWithActions viewingMode = getBPViewingModeWithActions();
     	textBodyString = viewingMode.getBodyPartContent(msgHeader, currAttachmentID);

        if (DEBUG) System.out.println("text:\n" + textBodyString );

        Parser parser = new Parser( textBodyString );

        Vector elements = parser.parse();
        prevScreen = mujMail.getDisplay().getCurrent();
        Browser browser = new Browser( elements );
        mujMail.getDisplay().setCurrent( browser );
    }*/
     void displayHTML(){
     textBodyString = msgHeader.getBodyPartContent(currAttachmentID);
    
   //  prevScreen = mujMail.getDisplay().getCurrent();
      addComponent(new Browser( new Parser( textBodyString ).parse() ));
    // mujMail.getDisplay().setCurrent( browser );
     setScrollable(false);
     }
    //#endif
   
    /**
     * @param mujMail - the main application object.
     */
    public MailForm(MujMail mujMail) {
        setScrollable(false);
        setLayout(lcduilwuit.Display.boxLayout_Y);
        this.mujMail = mujMail;
        //mailForm
//        init();
        back = new Command(Lang.get(Lang.BTN_BACK), Command.BACK, 0);
        reply = new Command(Lang.get(Lang.BTN_TB_REPLY), Command.OK, 2);
        //#ifdef MUJMAIL_FS
        exportToFS = new Command(Lang.get(Lang.BTN_MF_EXPORT_MAIL_TO_FS), Command.ITEM, 10);
        //#endif
        listAttachments = new Command(Lang.get(Lang.BTN_MF_ATTACHMENTS), Command.ITEM, 5);
        forward = new Command(Lang.get(Lang.BTN_TB_FORWARD), Command.ITEM, 6);
        quotedReply = new Command(Lang.get(Lang.BTN_TB_QUOTED_REPLY), Command.ITEM, 7);
        replyAll = new Command(Lang.get(Lang.BTN_TB_REPLY_ALL), Command.ITEM, 8);
        showAddresses = new Command(Lang.get(Lang.BTN_MF_EMAIL_ADDRS), Command.ITEM, 9);
        //address list
        addMailToBook = new Command(Lang.get(Lang.BTN_MF_ADD_EMAIL), Command.ITEM, 1);
        //attachments list
        deleteAttachment = new Command(Lang.get(Lang.BTN_MF_DEL_ATTACHMENTS), Command.ITEM, 1);
         edit = new Command(Lang.get(Lang.BTN_EDIT), Command.ITEM, 10);

       // reply = new ParentCommand(Lang.get(Lang.BTN_TB_REPLY),new Command[]{justReply,quotedReply,replyAll});

        addCommand(back);
        addCommand(forward);
        addCommand(listAttachments);
        addCommand(showAddresses);
        //#ifdef MUJMAIL_FS
//anup        addCommand(exportToFS);
        //#endif
        setCommandListener(this);
    }

    public void actionPerformed(ActionEvent evt) {

        com.sun.lwuit.Command c = evt.getCommand();
                    if (c == back) {

                if (getContext() == MailForm.MODE_BASIC) {
                    back();

                } // it was an attachment's detail so return to attachment list
                else {
                    attchList.show();
                }
            } else if (c == listAttachments) {
                listAttachments();
            } else if (c == showAddresses) {
                listMailAddr();
           //#ifdef MUJMAIL_FS
            } else if (c == exportToFS) {
                exportToFilesystem();
            //#endif
            } else if (c == forward) {
             //   if(!mailForm.isForwardSupported())
             //   {
             //   Alert alrt = new Alert("Not Supported");
             /// /  alrt.setString("Forwarding of mail with attchemnet not supported");;
             //   Display.getDisplay(this).setCurrent(alrt);
              //  }
               //     else
                    {
                        removeAll();
                new SendMail(mujMail).initForward(callBox, this);
                    }
            } //else if (c == mailForm.edit) {
                //commandAction(mailForm.callBox.edit, mailForm.callBox);
            //}
            else if (c == edit) {
                MessageHeader om = msgHeader;
                if (om != null) {
                         new SendMail(mujMail).edit(om, this);
                  }
            } else if (c == reply) {
                if (mujMail.getInBox().getSelectedIndex() < mujMail.getInBox().getStorage().getSize()) {
                    new SendMail(mujMail).reply(mujMail.getInBox().getSelectedHeader());
                }
            } else if (c == quotedReply) {
                if (mujMail.getInBox().getSelectedIndex() < mujMail.getInBox().getStorage().getSize()) {
                    new SendMail(mujMail).quotedReply(mujMail.getInBox().getSelectedHeader());
                }
            } else if (c == replyAll) {
                if (mujMail.getInBox().getSelectedIndex() < mujMail.getInBox().getStorage().getSize()) {
                    new SendMail(mujMail).replyAll(mujMail.getInBox().getSelectedHeader());
                }
           }
    }

   
    //#ifdef MUJMAIL_FS
    /**
     * Exports the mail to filesystem.
     */
    public void exportToFilesystem() {
       
        FileSystemMailExporter exporter = new FileSystemMailExporter(mujMail);
        exporter.exportMail(callBox, msgHeader);
    }
    //#endif

    /**
     * Shows a Form with actualized header information
     * @param header header that details will be shown
     * @param prevScreen the screen that will be displayed after user presses
     *  back button.
     */
    public void showHeader(MessageHeader header, Displayable prevScreen) {
        if (DEBUG) {
            System.out.println("DEBUG MailForm.showHeader(MessageHeader, Displayable) - displayable: " + prevScreen.getClass().toString());
        }
        this.prevScreen = prevScreen;
        msgHeader = header;
        setContext(MODE_BROWSE);

        if (headerForm == null) {
            headerForm = new Form(Lang.get(Lang.ML_HEADERS_DETAIL));
            headerForm.setScrollableX(false);
        }

        // remove old Items
        for (int i = headerForm.size(); i > 0; --i) {
            headerForm.delete(i - 1);
        }

        // append new ones
        String sender = Functions.emailOnly(header.getFrom());
       // if (mujMail.getAddressBook().getContactName(sender) != null) //if the sender is in adressbook, show his full name
        if(AddressBook.getContactName(sender)!=null)
        {
            //sender = mujMail.getAddressBook().getContactName(sender) + " <" + sender + ">";
            sender = AddressBook.getContactName(sender) + " <" + sender + ">";
        } else {
            sender = header.getFrom();
        }
        headerForm.append(new StringItem(Lang.get(Lang.ML_FROM) + " ", sender));
        if(header.getReplyTo()!=null && !header.getReplyTo().trim().equals("") )
             headerForm.append(new StringItem(Lang.get(Lang.EXTRA_REPLY_TO) + " ", header.getReplyTo()));
        headerForm.append(new StringItem(Lang.get(Lang.ML_RECIPIENTS) + " ", header.getRecipients()));
        headerForm.append(new StringItem(Lang.get(Lang.ML_SUBJECT) + " ", header.getSubject()));
        headerForm.append(new StringItem(Lang.get(Lang.ML_TIME) + " ", header.getTimeStr()));
        headerForm.append(new StringItem(Lang.get(Lang.ML_ATTACHMENTS) + " ", String.valueOf(header.getBodyPartCount())));

        headerForm.append(new StringItem(Lang.get(Lang.ML_SIZE) + " ", (header.getSize() < 10000 ? header.getSize() + " B" : (header.getSize() >> 10) + " kB")));


        headerForm.addCommand(back);
        mujMail.getDisplay().setCurrent(headerForm);
        headerForm.setCommandListener(new ActionListener(){

            public void actionPerformed(ActionEvent ae){
            if(ae.getCommand()==back){
                setContext(MailForm.MODE_BASIC);
                showPreviousScreen();
            }
        }});
    }

    //used to redownload a particular bodypart and then display the attachments list
    public void regetAndList(MessageHeader header, byte index) {
        if (header != null && index >= 0 && index < header.getBodyPartCount()) {
            msgHeader = header;
            bodyPartToRedown = header.getBpOriginalOrder(index);
            // TODO: (david) this will work with user folders??
            callBox = mujMail.getInBox();
            runMode = REDOWNLOAD_BODY;
            Thread t = new Thread(this);
            t.start();
            t.setPriority(Thread.MAX_PRIORITY);
        }
    }

    /**
     * Lists all attachments of the message
     */
    public void listAttachments() {

        // create a new object of List if necessary
        if (attchList == null) {

            attchList = new List(Lang.get(Lang.BTN_MF_ATTACHMENTS), Choice.IMPLICIT);
            deleteAttachment = new Command(Lang.get(Lang.BTN_MF_DEL_ATTACHMENTS), Command.ITEM, 2);
         //   redownAttchment = new Command(Lang.get(Lang.BTN_MF_REDOWN_ATTACHMENTS), Command.ITEM, 3);
//            displayAsText = new Command(Lang.get(Lang.BTN_MF_DISPLAY_AS_TEXT), Command.ITEM, 4);
            exportBPToFS = new Command(Lang.get(Lang.BTN_MF_EXPORT_BP_TO_FS), Command.ITEM, 5);
//            viewConverted = new Command(Lang.get(Lang.BTN_MF_VIEW_CONVERTED), Command.ITEM, 6);

            attchList.addCommand(back);
         //   if (msgHeader.getBox() == mujMail.getInBox()) {
        //        attchList.addCommand(redownAttchment);
       //     }
            attchList.addCommand(deleteAttachment);
    //        attchList.addCommand(displayAsText);
            attchList.addCommand(exportBPToFS);
           // attchList.addCommand(new Command("View"));
            //Anup       attchList.addCommand(viewConverted);
            attchList.setCommandListener(new ActionListener(){
                
            public void actionPerformed(ActionEvent ae)
            {
                
            com.sun.lwuit.Command c = ae.getCommand();
            if (c == back) {

                //if (mailForm.getContext() == MailForm.MODE_LIST) {
                    back();
               // } else {
                //    mailForm.setContext(MailForm.MODE_BASIC);
               //     myDisplay.setCurrent(mailForm);
               // }
            } else if (c == deleteAttachment) {
                deleteBodyPart((byte) (attchList.getSelectedIndex()));
            } else if (c == showAddresses) {
                listMailAddr();
            //#ifdef MUJMAIL_FS
            } else if (c == exportBPToFS) {
                exportBPToFS((byte) attchList.getSelectedIndex());
            //#endif
            /* } else if (c == mailForm.displayAsText) {
                mailForm.viewBodyPart((byte) (mailForm.attchList.getSelectedIndex()), MailForm.BP_VIEWING_MODE_AS_TEXT);//BPViewingModes.AS_TEXT);
           } else if (c == mailForm.viewConverted) {
            	mailForm.viewBodyPart((byte) (mailForm.attchList.getSelectedIndex()), MailForm.BPViewingModes.CONVERTED );
             * */
            } else {
                viewBodyPart((byte) (attchList.getSelectedIndex()), MailForm.BP_VIEWING_MODE_AS_NOT_SPECIFIED);//MailForm.BPViewingModes.NOT_SPECIFIED);
            }
            }});
        }

        for (int i = attchList.size(); i > 0; i--) {
            attchList.delete(i - 1);
        }

        System.out.println(msgHeader);
        int bodyPartCount = msgHeader.getBodyPartCount();
        for (byte i = 0; i < bodyPartCount; i++) {
            // choose different icons according to the bodypart type
            String prefix = msgHeader.getBpState(i) == BodyPart.BS_COMPLETE ? "" : " [!] ";
            switch (msgHeader.getBpType(i)) {
                case BodyPart.TYPE_TEXT:
                    attchList.append(prefix + msgHeader.getBodyPart(i).getHeader().getName() + " (" +
                            (msgHeader.getBodyPart(i).getSize() > 1024 ? (msgHeader.getBodyPart(i).getSize() >> 10) + "kB" : msgHeader.getBodyPart(i).getSize() + "B") + ")",
                            Functions.getIcon("attch_txt.png"));
                    break;
                case BodyPart.TYPE_MULTIMEDIA:
                    attchList.append(prefix + msgHeader.getBodyPart(i).getHeader().getName() + " (" +
                            (msgHeader.getBodyPart(i).getSize() > 1024 ? (msgHeader.getBodyPart(i).getSize() >> 10) + "kB" : msgHeader.getBodyPart(i).getSize() + "B") + ")",
                            Functions.getIcon("attch_image.png"));
                    break;
                case BodyPart.TYPE_HTML:
                    attchList.append(prefix + msgHeader.getBodyPart(i).getHeader().getName() + " (" +
                            (msgHeader.getBodyPart(i).getSize() > 1024 ? (msgHeader.getBodyPart(i).getSize() >> 10) + "kB" : msgHeader.getBodyPart(i).getSize() + "B") + ")",
                            Functions.getIcon("attch_html.png"));
                    break;
                case BodyPart.TYPE_APPLICATION:
                case BodyPart.TYPE_OTHER:
                    attchList.append(prefix + msgHeader.getBodyPart(i).getHeader().getName() + " (" +
                            (msgHeader.getBodyPart(i).getSize() > 1024 ? (msgHeader.getBodyPart(i).getSize() >> 10) + "kB" : msgHeader.getBodyPart(i).getSize() + "B") + ")",
                            Functions.getIcon("attch_unknown.png"));
                    break;

            }
        }
        mujMail.getDisplay().setCurrent(attchList);
    }

    public boolean isForwardSupported() {
        int bodyPartCount = msgHeader.getBodyPartCount();
        for (byte i = 0; i < bodyPartCount; i++) {
            switch (msgHeader.getBpType(i)) {
                case BodyPart.TYPE_TEXT:
                case BodyPart.TYPE_HTML:
                    break;
                default:
                    return false;
            }
        }
        return true;
    /*int attachmentCount = msgHeader.getAttachementCount();
    for (byte i = 0; i < attachmentCount; i++) {
    BodyPart bp = msgHeader.getAttachement(i);
    Header  h = bp.getHeader();

    }
    switch (msgHeader.getBpType(i))
    {
    case BodyPart.TYPE_TEXT:
    case BodyPart.TYPE_HTML:
    break;
    default:return false;
    }*/
    }

    /**
     * Shows a list of e-mail addresses in a MULTIPLE list.
     */
    public void listMailAddr() {
        if (mailAdrList == null) {
            mailAdrList = new List(Lang.get(Lang.BTN_MF_EMAIL_ADDRS), Choice.MULTIPLE);
            mailAdrList.addCommand(back);
            mailAdrList.addCommand(addMailToBook);
            mailAdrList.setCommandListener(new ActionListener(){
            public void actionPerformed(ActionEvent ae)
            {
                if (ae.getCommand()==back) {
                show();
                } else if (ae.getCommand() == addMailToBook) {
                saveContacts();
            }
            }
            });
        }
        // delete old items
        for (int i = mailAdrList.size(); i > 0; i--) {
            mailAdrList.delete(i - 1);
        }

        // refresh address' Vector and List
        Vector addr = Functions.parseRcp(msgHeader.getRecipients());
        addr.addElement(Functions.emailOnly(msgHeader.getFrom()));

        for (int i = 0; i < addr.size(); i++) {
            mailAdrList.append((String) addr.elementAt(i), null);
        }
        mujMail.getDisplay().setCurrent(mailAdrList);
    }

    /**
     * Save all checked email addresses in the <code>mailAdrList</code>.
     */
    public void saveContacts() {
        boolean[] checked = new boolean[mailAdrList.size()];
        mailAdrList.getSelectedFlags(checked);
        AddressBook.Contact contact;
        for (int i = 0; i < mailAdrList.size(); ++i) {
            if (checked[i]) {
                contact = new AddressBook.Contact("", mailAdrList.getString(i), "");
                try {
                //    mujMail.getAddressBook().saveContact(contact);
                    AddressBook.directSaveContactToDatabase(contact);
                } catch (MyException ex) {
                    ex.printStackTrace();
                }
            }
        }
        mujMail.getDisplay().setCurrent(this);
    }

    /**
     * This method completely deletes a method attachment, that is chosen. This bodypart must be deleted from both
     * <code> bodyParts Vector </code> and <code> MailDb </code> that is done by <code>deleteBodyPart</code> method.
     * @param ID of the attachment. It is attchList.getSelectedIndex + 1.
     * @see MessageHeader
     */
    public void deleteBodyPart(byte ID) {
        synchronized (msgHeader) {
            byte bodyPartCount = msgHeader.getBodyPartCount();
            if (bodyPartCount == 0) {
                mujMail.alert.setAlert(this, this, Lang.get(Lang.ALRT_MF_NO_ATTACHMENTS), MyAlert.DEFAULT, AlertType.ERROR);
                return;
            }
            if (0 <= ID && ID < bodyPartCount) {
                try {
                    msgHeader.getBodyPart(ID).getStorage().deleteContent();
                    attchList.delete(ID);
                    msgHeader.removeBodyPart(ID);
                    //to prevent accessing non-existing bodypart
                    if (firstViewable == ID) {
                        firstViewable = -1;
                    }
                    if (currAttachmentID == ID) {
                        currAttachmentID = firstViewable;
                    }

                    msgHeader.saveHeader(); //we have to update info about msgHeader as well
                } catch (MyException ex) {
                    mujMail.alert.setAlert(attchList, callBox, Lang.get(Lang.ALRT_MF_DEL_ATT) + Lang.get(Lang.FAILED) + ex.getDetails(), MyAlert.DEFAULT, AlertType.ERROR);
                    msgHeader.notify();
                    return;
                }
                mujMail.alert.setAlert(attchList, attchList, Lang.get(Lang.ALRT_MF_DEL_ATT) + Lang.get(Lang.SUCCESS), MyAlert.DEFAULT, AlertType.INFO);
            }
            msgHeader.notify();
        }
    }

    /**
     * Thread method that serves to load body either from MailDB or from remote server.
     */
    public void run() {
        setContext(MODE_LIST);
        switch (runMode) {
            case LOAD_BODY:
                try {

                    /* if(msgHeader.getSize()>mujmail.Settings.MAX_MAIL_SIZE_FOR_DOWNLOAD)
                    {
                    mujMail.alert.setAlert(this, callBox, "Email Size is more than "+(mujmail.Settings.MAX_MAIL_SIZE_FOR_DOWNLOAD/1000)+"KB", MyAlert.DEFAULT, AlertType.ERROR);
                    return;
                    }*/
                    if (loadBody(msgHeader) == null) { //try to load the body of the mail
                        mujMail.alert.setAlert(this, callBox, Lang.get(Lang.ALRT_MF_LOAD_BODY) + Lang.get(Lang.FAILED), MyAlert.DEFAULT, AlertType.ERROR);
                        return;
                    }

                    //only inBox needs a counter for unread mails
                    if (msgHeader.readStatus == MessageHeader.NOT_READ && msgHeader.getBox() == mujMail.getInBox()) {
                        msgHeader.readStatus = MessageHeader.READ;

                        //Seen flag is set automatically when
                        //FETCH BODY is called -> no need to set \Seen flag
                        /*
                        MailAccount msgAcct = (MailAccount)mujMail.mailAccounts.get(msgHeader.accountID);

                        //Set '\Seen' flag on server if it's an IMAP account
                        if (msgAcct.type == MailAccount.IMAP)
                        {
                        msgAcct.protocol.setFlags(msgHeader, "(\\Seen)");
                        }
                         */

                        try {
                            msgHeader.saveHeader(); //update new data into DBase
                        } catch (MyException me) {
                        }
                        ((InBox) msgHeader.getBox()).changeUnreadMails(-1);
                    }
                    firstViewable = getFirstViewableBody(msgHeader); //find the first viewable bodypart;
                    if (firstViewable == -1) { //non are viewable
                        listAttachments();
//                        attchList.addCommand(showHeader);
                        attchList.addCommand(showAddresses);
//                        attchList.addCommand(delete);
                        attchList.addCommand(forward);
                        attchList.addCommand(edit);

                        //#ifdef MUJMAIL_FS
                        attchList.addCommand(exportToFS);
                        //#endif
                        mujMail.alert.setAlert(this, attchList, Lang.get(Lang.ALRT_MF_NO_VIEWABLE_BODY), MyAlert.DEFAULT, AlertType.INFO);
                    } else { //there are some viewable bodyparts
                  //      BodyPart bp = msgHeader.getBodyPart(firstViewable);
                        currAttachmentID = firstViewable;
                        setContext(MODE_BASIC);
                        newTextSelected = true;// bp.getAutoViewingMode().initDisplayingVariables(this);

                        //   repaint();
                        mujMail.getDisplay().setCurrent(this);
                       
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                    back();
                    mujMail.alert.setAlert(this, callBox, Lang.get(Lang.ALRT_MF_LOAD_BODY) + Lang.get(Lang.FAILED) /*+ ex*/, MyAlert.DEFAULT, AlertType.ERROR);
                } catch (Error e) {
                    e.printStackTrace();
                    back();
                    mujMail.alert.setAlert(this, callBox, Lang.get(Lang.ALRT_MF_LOAD_BODY) + Lang.get(Lang.FAILED) /*+ e*/, MyAlert.DEFAULT, AlertType.ERROR);
                }
                break;

            case REDOWNLOAD_BODY:
                /*if(msgHeader.getSize()>mujmail.Settings.MAX_MAIL_SIZE_FOR_DOWNLOAD)
                {
                mujMail.alert.setAlert(this, callBox, "Email Size is more than "+(mujmail.Settings.MAX_MAIL_SIZE_FOR_DOWNLOAD/1000)+"KB", MyAlert.DEFAULT, AlertType.ERROR);
                return;
                }*/
                synchronized (msgHeader) {
                    mujMail.getInBox().regetBody(msgHeader, bodyPartToRedown);
                    mujMail.getDisplay().setCurrent(callBox);
                    try {
                        msgHeader.wait();
                    } catch (Exception ignored) {
                    }
                }
                listAttachments();
                break;
        }
    }

  
    /**
     * <p>
     * Is used to display body of a message with all attachments. Firstly, it
     * shows just a textual part of a body. If the message contains some other
     * attachments, the Canvas will have listAttachments Command to display it.
     * <p>
     * Must be run in separate thread.
     *
     * @param mh - {@link MessageHeader} that will be displayed.
     * @param callBox - this is a screen, that will be shown after an user clicks back button
     * Viewing must be run a in different thread, other it would cause the mujmail main thread unable to
     * perform any other vital tasks - commandListening, displaying dialog windows!!!
     */
    public void viewMessage(MessageHeader msgHeader, TheBox callBox) {
        if (msgHeader == null) {
            return;
        }
        bpViewingMode = BP_VIEWING_MODE_AS_NOT_SPECIFIED;

        this.callBox = callBox;
        this.msgHeader = msgHeader;
        runMode = LOAD_BODY;
        Thread t = new Thread(this);
        t.start();
        t.setPriority(Thread.MAX_PRIORITY);
    }

    //#ifdef MUJMAIL_FS
    /**
     * Exports given bodypart to filesystem.
     * @param ID ID of the BodyPart to be exported.
     */
    void exportBPToFS(byte ID) {
        if (((msgHeader.getBodyPart(ID)).getStorage()) instanceof FSStorage) {
            FSStorage strg = (FSStorage) (msgHeader.getBodyPart(ID).getStorage());

            mujMail.alert.setAlert(this, callBox, Lang.get(Lang.EXTRA_YOU_CAN_FIND_THIS_FILE) + strg.getFileURL(), MyAlert.DEFAULT, AlertType.ERROR);
            return;
        }
        FileSystemBodyPartExporter.exportBPToFS(this, msgHeader, ID);
    }
    //#endif

    /**
     * Displays the chosen bodypart.
     * @param ID ID of the BodyPart.
     * @param viewingMode the viewing mode of the body part
     */
    public boolean isViewable(int type)
    {
        if(type>BP_VIEWING_MODE_AS_NOT_SPECIFIED)
            return false;
        else
            return true;
    }

    public void viewBodyPart(byte ID, int viewingMode ){//BPViewingModes viewingMode) {
        if (DEBUG) {
            System.out.println("DEBUG MailForm.viewBodyPart(ID=" + ID + ", viewingMode=" + viewingMode + ")");
        }
        BodyPart actBodyPart = msgHeader.getBodyPart(ID);
        if (DEBUG) {
            System.out.println("DEBUG MailForm.viewBodyPart(byte, BPViewingModes) - " + actBodyPart);
        }
        bpViewingMode = viewingMode;

       /* if (!getBPViewingModeWithActions().isViewable(actBodyPart, attchList)) {
            if (DEBUG) {
                System.out.println("DEBUG MailForm.viewBodyPart(byte, BPViewingModes) - BodyPart is not viewable");
            }
            return;
        }*/
        if(!isViewable(viewingMode))
        {
            Dialog.show("", Lang.get(Lang.EXTRA_FILE_TYPE_NOT_SUPPORTED), Lang.get(Lang.BTN_OK), "");
            return ;
        }

        if (0 <= ID && ID < msgHeader.getBodyPartCount()) {
            if (ID != firstViewable) //another bodypart than firstViewable was chosen
            {
                setContext(MODE_BROWSE);
            } else {
                setContext(MODE_BASIC);
            } //prevents viewing the same bodypart twice

           /* if (!getBPViewingModeWithActions().prepareForViewingBP(actBodyPart, ID, this)) {
                return;
            }*/

            currAttachmentID = ID;
         //   repaint();
        }
        mujMail.getDisplay().setCurrent(this);
    }

    private byte getFirstViewableBody(MessageHeader mh) {
        byte bpCount = mh.getBodyPartCount();
        byte i;
        BodyPart bp;
        for (i = 0; i < bpCount; i++) {
            bp = mh.getBodyPart((byte) i);
            if (bp.getAutoViewingMode() != BP_VIEWING_MODE_AS_NO_VIEW){//BPViewingModes.NO_VIEW) {
                return i;
            }
        }
        return -1;
    }

    /**
     * Loads and displays the first text or HTML part of a body.
     * If the body has not been downloaded yet, than it is necessary to retrieve the whole message from the remote server.
     * @param mh - {@link MessageHeader} that body should be read.
     * @return first bodyPart String. If there is no textual part of the body, then it returns a <code> String </code> informing
     * about it.
     */
    public MessageHeader loadBody(MessageHeader mh) {
        this.msgHeader = mh;
        // if body is in the RecordStore
        if (mh.getBodyPartCount() > 0) {
            return mh;
        } // body must be downloaded
        else {
            //its not inBox or user folder (ie trash), but we would save the mail's body the inbox
            //and it would cause a mess in Database
            if (!(mh.getBox() instanceof InBox)) {
                return null;
            }
            synchronized (mh) {
                ((InBox) mh.getBox()).getBody(mh);
                try {
                    mh.wait();
                } catch (Exception ex) {
                }
            }
            if (mh.getBodyPartCount() == 0) //message could not be downloaded
            {
                return null;
            }

            return mh;
        }

    }

    /**
     * Changes a graphical context, which is used to recognize, what is to be displayed. There are three possible
     * choices.
     * <ol>
     * 	<li> TEXT_MODE context - is used to display plain text.
     * 	<li> MODE_BROWSE context - is used to display image attachments.
     * 	<li> MODE_LIST context - is used when some form or list is supposed to be displayed .
     * </ol>
     *
     * <p> It sets up appropriate Commands to the listAttachments object.
     * @param contextID - graphical context.
     */
    public void setContext(byte contextID) {
        this.contextID = contextID;
        currDisplay = 0;

        switch (contextID) {
            // text/html context
            case MODE_BASIC:
                if (msgHeader.messageFormat == MessageHeader.FRT_MULTI && msgHeader.getBodyPartCount() > 1) {
                    addCommand(listAttachments);
                }
                addCommand(back);
                addCommand(listAttachments);
//                addCommand(showHeader);
                addCommand(showAddresses);
                //#ifdef MUJMAIL_FS
          //anup      addCommand(exportToFS);
                //#endif
                break;

            // attachment contexts
            case MODE_BROWSE:
                removeCommand(listAttachments);
//                removeCommand(showHeader);
                removeCommand(showAddresses);
                //#ifdef MUJMAIL_FS
                removeCommand(exportToFS);
                //#endif
                break;
        }
    }

    /**
     * Returns a contextID value.
     */
    public byte getContext() {
        return contextID;
    }

    /**
     * Shows an *.PNG image attachment on the display. We use <code>scaleImage</code>
     * function to resize image. Since MIDP 1.0 dosn't support loading of pixels from the
     * image to the buffer, the resized image will lose some information compared to the
     * previous one.
     */
        private void drawImage() {
        // clear the display
        //  g.setColor(BACKGROUND_COLOR);
        // g.fillRect(0, 0, getWidth(), getHeight());

        // encoding is base64
        if (msgHeader.getBpEncoding(currAttachmentID) == BodyPart.ENC_BASE64) { //||
            // msgHeader.getBpEncoding(currAttachmentID) == BodyPart.ENC_NORMAL){

            try {
                byte[] data = msgHeader.getBodyPartContentRaw(currAttachmentID);
                if (data == null) {
                    throw new MyException(MyException.DB_CANNOT_LOAD_BODY);
                }
                Image img = Image.createImage(data, 0, data.length);
                int imgWidth = img.getWidth();
                int imgHeight = img.getHeight();
                data = null;
                System.gc();
                short width = (short) getWidth(), height = (short) getHeight();
                short dstHeight, dstWidth;
                int widthRatio = (width << 16) / imgWidth;
                int heightRatio = (height << 16) / imgHeight;

                if (imgWidth <= width && imgHeight <= height) {
                    //drawImage(img, ((width - imgWidth) >> 1), ((height - imgHeight) >> 1));//, Graphics.TOP | Graphics.LEFT);
                //    setLayout(new BorderLayout());
                    addComponent(/*BorderLayout.CENTER, */new Label(img));
                } // if image is bigger than display then scale it.
                else {
                    if (widthRatio > heightRatio) {
                        dstHeight = height;
                        dstWidth = (short) (((imgWidth * heightRatio) >> 16)-4);
                        //setLayout(new BorderLayout());
                        addComponent(/*BorderLayout.CENTER,*/ new Label(Functions.scaleImage(img, dstWidth, dstHeight)));
                    //g.drawImage(Functions.scaleImage(img, dstWidth, dstHeight), ((width - dstWidth) >> 1), 0, Graphics.TOP | Graphics.LEFT);
                    } else {
                        dstHeight = (short) (((imgHeight * widthRatio) >> 16)-4);
                        dstWidth = width;
                   //     setLayout(new BorderLayout());
                        addComponent(/*BorderLayout.CENTER, */new Label(Functions.scaleImage(img, dstWidth, dstHeight)));
                    //g.drawImage(Functions.scaleImage(img, dstWidth, dstHeight), 0, ((height - dstHeight) >> 1), Graphics.TOP | Graphics.LEFT);
                    }
                }
            } catch (MyException ex) {
                back();
                mujMail.alert.setAlert(this, callBox, ex.getDetails(), MyAlert.DEFAULT, AlertType.ERROR);
            } catch (Exception ex) {
                back();
                mujMail.alert.setAlert(this, callBox, Lang.get(Lang.ALRT_MF_VIEW_ATT) + Lang.get(Lang.FAILED)/* + " " + ex.toString()*/, MyAlert.DEFAULT, AlertType.ERROR);
            } catch (Error e) {
                System.gc();
                back();
                mujMail.alert.setAlert(this, callBox, Lang.get(Lang.ALRT_MF_VIEW_ATT) + Lang.get(Lang.FAILED) /*+ " " + e.toString()*/, MyAlert.DEFAULT, AlertType.ERROR);
            }
        } else if (msgHeader.getBpEncoding(currAttachmentID) == BodyPart.ENC_NORMAL) {
            byte attID = currAttachmentID;
            back();
            //msgHeader.getBodyPart(currAttachmentID).
            if (((msgHeader.getBodyPart(attID)).getStorage()) instanceof FSStorage) {
                FSStorage strg = (FSStorage) (msgHeader.getBodyPart(attID).getStorage());

                mujMail.alert.setAlert(this, callBox,Lang.get(Lang.EXTRA_YOU_CAN_FIND_THIS_FILE) + strg.getFileURL(), MyAlert.DEFAULT, AlertType.ERROR);

            }

        } else {
            back();
            mujMail.alert.setAlert(this, callBox, Lang.get(Lang.ALRT_MF_UNSUPPORTED_FORMAT), MyAlert.DEFAULT, AlertType.ERROR);
        }
    }


    public void onShow() {
        updateEditButton();
        if (getFirstViewableBody(msgHeader) == -1 ||
                (getFirstViewableBody(msgHeader) != firstViewable && contextID != MODE_BROWSE)) {
            back();
            return;
        }
        try{
        setContextCommand();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        removeAll();

        switch (contextID) {
            case MODE_LIST:
                listAttachments();
                break;

            case MODE_BASIC:
                //getBPViewingModeWithActions().prepareBeforeDisplayingBP(this);
                currAttachmentID = firstViewable; //useful when the attachments list returns focus back to the mailform

            case MODE_BROWSE:   // and MODE_BASIC
             /* BodyPart bp= msgHeader.getBodyPart(currAttachmentID);
                if(bp.getAutoViewingMode() instanceof MailForm.BPViewingModes.PlainTextMode )
                {

                }*/

                displayBodyPart();

               /* if (!getBPViewingModeWithActions().displayBodyPart(this)) {
                    return;
                }*/

                break;
        }
    }
    private void displayBodyPart()
    {
       
        removeAll();
         Browser.removeAllFromStack();
        System.gc();
        setScrollable(true);
        if (((msgHeader.getBodyPart(currAttachmentID)).getStorage()) instanceof FSStorage) {
            FSStorage strg = (FSStorage) (msgHeader.getBodyPart(currAttachmentID).getStorage());

            mujMail.alert.setAlert(this, callBox, Lang.get(Lang.EXTRA_YOU_CAN_FIND_THIS_FILE) + strg.getFileURL(), MyAlert.DEFAULT, AlertType.ERROR);
            return;
        }
        if(bpViewingMode==BP_VIEWING_MODE_AS_NOT_SPECIFIED)
            bpViewingMode=msgHeader.getBodyPart(currAttachmentID).getAutoViewingMode();
        switch(bpViewingMode)
        {
            case BP_VIEWING_MODE_AS_TEXT:
            {
            	preparenewText();
                if (currAttachmentID != firstViewable )
                    newTextSelected = true;
                setScrollable(false);
                String str = Functions.removeTags(textBodyString);
                byte[] strByte = str.getBytes();
                if(strByte.length>MAX_SIZE_TEXT)
                {
                    str = new String(strByte,0,MAX_SIZE_TEXT)+" ["+Lang.get(Lang.EXTRA_MSG_TRUCATED)+"]";
                }
                TextArea txt = new TextArea(str,5,5,TextArea.UNEDITABLE){
                    public int getRows(){
                        if(isGrowByContent()){
                            return getLines();
                        }else{
                            return super.getRows();
                        }
                    }
                };
                addComponent(txt);
                break;
            }
           case BP_VIEWING_MODE_AS_IMAGE:

                //byte[] data = msgHeader.getBodyPartContentRaw(currAttachmentID);
               // Image img=Image.createImage(data,0,data.length);
               // append(img);
               drawImage();
                break;
          case  BP_VIEWING_MODE_AS_HTML:
          {
              //#ifdef MUJMAIL_HTML
              displayHTML();
              //#endif
              /*  preparenewText();
                if (currAttachmentID != firstViewable )
                    newTextSelected = true;
                setScrollable(false);
                TextArea txt = new TextArea(textBodyString,5,5,TextArea.UNEDITABLE){
                 public int getRows(){
                        if(isGrowByContent()){
                            return getLines();
                        }else{
                            return super.getRows();
                        }
                    }
                };
                addComponent(txt);*/
                break;
          }
            default:
                mujMail.alert.setAlert(this, callBox, Lang.get(Lang.EXTRA_FILE_TYPE_NOT_SUPPORTED), MyAlert.DEFAULT, AlertType.ERROR);
                break;

        }
    }
    private void preparenewText()
    {
        textBodyString = msgHeader.getBodyPartContent(currAttachmentID);

        if (textBodyString == null) {
            Displayable nextDisp;
            if (contextID == MODE_BROWSE) {
                nextDisp = attchList;
            } else {
                nextDisp = callBox;
            } //we need to return the focus back to the box
            mujMail.alert.setAlert(this, nextDisp, Lang.get(Lang.ALRT_MF_LOAD_BODY) + Lang.get(Lang.FAILED), MyAlert.DEFAULT, AlertType.ERROR);
            //throw new MyException(0);
        }
         if (Settings.replaceTabs) {
                textBodyString = textBodyString.replace('\t', ' ');
            }
        if (textBodyString.equals("")) {
            textBodyString = "<" + Lang.get(Lang.ML_BODY) + Lang.get(Lang.EMPTY) + ">\r\n.\r\n";
        }

    }
    /*protected String preprocessBodyPartBeforeDisplaying(MailForm mailFrom) {
        //#ifdef MUJMAIL_HTML
        return mailFrom.textBodyString;
    //#else
//#             return Functions.removeTags(mailFrom.textBodyString);
    //#endif
    }*/
    private void setContextCommand() {
        if (msgHeader.getBox() == mujMail.getInBox()) {
            addCommand(reply);
            addCommand(quotedReply);
            addCommand(replyAll);
        } else {
            removeCommand(reply);
            removeCommand(quotedReply);
            removeCommand(replyAll);
        }

    }

    //defaults values
    public void back() {
        currDisplay = 0;
        currAttachmentID = 0;
        textBodyDisplays = null;
        textBodyString = null;
        attchList = null;
        mailAdrList = null;
        headerForm = null;
        removeAll();
        mujMail.getDisplay().setCurrent(callBox);
         Browser.removeAllFromStack();
    }/*
    private void init() {
      setMenuTransitions(null, null);
      setMenuCellRenderer(new DefaultListCellRenderer() {
          private boolean isSubMenu;
          public Component getListCellRendererComponent(com.sun.lwuit.List list, Object value, int index, boolean isSelected) {
              isSubMenu = value != null && value instanceof ParentCommand;
              return (super.getListCellRendererComponent(list, value, index, isSelected));
          }

          public void paintBackground(Graphics g) {
              super.paintBackground(g);
              if(isSubMenu) {
                  int oldColor = g.getColor();
                  if(hasFocus()) {
                      g.setColor(getStyle().getFgSelectionColor());
                  } else {
                      g.setColor(getStyle().getFgColor());
                  }
                  int leftPoint = getX() + getWidth() - 10;
                  int rightPoint = getX() + getWidth() - 2;
                  int centerPoint = getY() + (getHeight() / 2);
                  int topPoint = centerPoint - 4;
                  int bottomPoint = centerPoint + 4;
                  g.drawLine(leftPoint, topPoint, rightPoint, centerPoint);
                  g.drawLine(leftPoint, bottomPoint, rightPoint, centerPoint);
                  g.drawLine(leftPoint, topPoint, leftPoint, bottomPoint);
                  g.setColor(oldColor);
              }
          }
      });
  }
 protected com.sun.lwuit.List createCommandList(Vector commands) {
      com.sun.lwuit.List commandList = super.createCommandList(commands);
      SelectionMonitor s = new SelectionMonitor(commandList);
      commandList.addSelectionListener(s);
      commandList.addActionListener(s);
      return commandList;
  }

  protected com.sun.lwuit.Command showMenuDialog(Dialog menu) {
      menuDialog = menu;
      com.sun.lwuit.Command c = super.showMenuDialog(menu);
      menuDialog = null;
      return c;
  }
    private static final int SUBMENU_POPUP_DELAY = 1000;
    private Dialog menuDialog;
    private ParentCommand selection;

  class SelectionMonitor implements SelectionListener, Animation, ActionListener {
      private com.sun.lwuit.List commandList;
      private long selectTime;
      public SelectionMonitor(com.sun.lwuit.List commandList) {
          this.commandList = commandList;
      }

      public boolean animate() {
          // we use the animate method as a timer, gauging the time that passed since a selection
          // was made
          if(selection == null) {
              menuDialog.deregisterAnimated(this);
          } else {
             if(System.currentTimeMillis() - selectTime >= SUBMENU_POPUP_DELAY) {
                  menuDialog.deregisterAnimated(this);
                  showSubmenu();
              }
          }

          return false;
      }

      public void selectionChanged(int oldSelected, int newSelected) {
          Object o = commandList.getSelectedItem();
          if(o != null && o instanceof ParentCommand) {
              // cause the animation of the parent form to be invoked
              menuDialog.registerAnimated(this);
              selection = (ParentCommand)o;
              selectTime = System.currentTimeMillis();
          } else {
              selection = null;
          }
      }

      public void paint(Graphics g) {
      }

      public void actionPerformed(ActionEvent evt) {
          menuDialog.deregisterAnimated(this);
          if(selection != null) {
              showSubmenu();
          }
      }

      private void showSubmenu() {
          final Dialog subMenu = new Dialog();
          final com.sun.lwuit.List content = new com.sun.lwuit.List
                  (selection.getChildren());
          content.getStyle().setBgTransparency(0);
          content.addActionListener(new ActionListener() {
              public void actionPerformed(ActionEvent evt) {
                  subMenu.dispose();
                  Command c = (Command)content.getSelectedItem();
                  final ActionEvent e = new ActionEvent(c);
                 // c.actionPerformed(e);
                  actionCommand(c);
                  System.out.println("**********Command"+c);
                //  new Thread(){
                 //   public void run(){
                      mujMail.actionPerformed(e);
                       System.out.print("GET CURRENT IS"+mujMail.getDisplay().getCurrent());
                       actionCommand(c);
                       //
              //}
                //  }.start();

              }
          });
          subMenu.setLayout(new BorderLayout());
          subMenu.addComponent(BorderLayout.CENTER, content);
          Command select = new Command("Select") {
              public void actionPerformed(ActionEvent evt) {
                  Command c = (Command)content.getSelectedItem();
                  ActionEvent e = new ActionEvent(c);
                  c.actionPerformed(e);
                  actionCommand(c);
              }
          };
          final Dialog oldMenuDialog = menuDialog;
          Command cancel = new Command("Cancel") {
              public void actionPerformed(ActionEvent evt) {
                  oldMenuDialog.show();
              }
          };
          subMenu.setDialogStyle(menuDialog.getDialogStyle());
          subMenu.addCommand(cancel);
          subMenu.addCommand(select);
          subMenu.show(getHeight() / 2 - 20, 20, getWidth() / 4, 20, true, true);
      }
  }





    class ParentCommand extends Command {

        private Command[] children;

        public ParentCommand(String name, Command[] children) {
            super(name);
            this.children = children;
        }

        public Command[] getChildren() {
            return children;
        }
    }*/

}


